﻿// Copyright 2007-2008 Rory Plaire (codekaizen@gmail.com)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;

namespace NPack.Interfaces
{
    /// <summary>
    /// Defines a vector buffer for storing vector data in a specific format.
    /// </summary>
    /// <typeparam name="TVector">The type of vector to store.</typeparam>
    /// <typeparam name="TComponent">The type of component in the vector.</typeparam>
    /// <remarks>
    /// <para>
    /// A vector buffer allows specific storage of vectors in memory. This is useful
    /// since modern hardware treats vector data specially, and a specific storage
    /// format can take advantage of these capabilities. For example, SSE and SSE2 instructions
    /// are found on almost all of the non-embedded, general-purpose CPUs on the market,
    /// and these instructions work best when memory is aligned to 16-byte boundaries. 
    /// Using a Structure of Arrays (SoA) data format is also preferable when performing
    /// matrix computations.
    /// </para>
    /// </remarks>
    [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
    public interface IVectorBuffer<TVector, TComponent> : IEnumerable<TVector>
        where TVector : IBufferedVector<TVector, TComponent>, IEquatable<TVector>, IComparable<TVector>, IComputable<Double, TVector>
        where TComponent : IEquatable<TComponent>, IComparable<TComponent>, IComputable<TComponent>, IConvertible, IFormattable
    {
        TVector Add(params TComponent[] components);
        Int32 Add(IVector<TComponent> vector);
        Int32 Add(TVector vector);
        void Clear();
        Boolean Contains(IVector<TComponent> item);
        Boolean Contains(TVector item);
        void CopyTo(TVector[] array, Int32 startIndex, Int32 endIndex);
        Int32 Count { get; }
        IVectorFactory<TVector, TComponent> Factory { get; }
        Boolean IsReadOnly { get; }
        Int32 MaximumSize { get; set; }
        void Remove(Int32 index);
        event EventHandler SizeIncreased;
        event CancelEventHandler SizeIncreasing;
        TVector this[Int32 index] { get; set; }
        Int32 VectorLength { get; }
        event EventHandler<VectorOperationEventArgs<TVector, TComponent>> VectorChanged;
    }

    public enum VectorOperation
    {
        None = 0,
        Changed,
        Removed
    }

    [Serializable]
    public class VectorOperationEventArgs<TVector, TComponent> : EventArgs
        where TVector : IBufferedVector<TVector, TComponent>, IEquatable<TVector>, IComparable<TVector>, IComputable<Double, TVector>
        where TComponent : IEquatable<TComponent>, IComparable<TComponent>, IComputable<TComponent>, IConvertible, IFormattable
    {
        private readonly VectorOperation _operation;
        private readonly Int32 _index;
        private readonly TVector _vector;

        public VectorOperationEventArgs(VectorOperation operation, Int32 index, TVector vector)
        {
            _operation = operation;
            _index = index;
            _vector = vector;
        }

        public VectorOperation Operation 
        { 
            get { return _operation; }
        }

        public Int32 Index
        {
            get { return _index; }
        }

        public TVector Vector
        {
            get { return _vector; }
        }

        public override String ToString()
        {
            return String.Format("[{0}] Operation: {1}", GetType(), Operation);
        }

        public override Int32 GetHashCode()
        {
            Int32 hash = _operation.GetHashCode();
            return (hash * 37) ^ hash;
        }

        public override Boolean Equals(object obj)
        {
            VectorOperationEventArgs<TVector, TComponent> other = 
                obj as VectorOperationEventArgs<TVector, TComponent>;

            if (ReferenceEquals(other, null))
            {
                return false;
            }

            return _operation == other._operation;
        }
    }
}